<?php
/**
 * Created by PhpStorm.
 * User: Qch
 * Date: 2016/8/13
 * Time: 20:55
 */

namespace J;

use J\Util\Config;
use J\Util\File;
use J\Util\FileAsynchronizer;


/**
 * 单例类
 */
trait Single
{
    /**
     * @var []
     */
    protected static $instance  = [];

    /**
     * Single constructor.
     */
    private function __construct(){}

    /**
     * @return static
     */
    final public static function getInstance()
    {
        $class_name = get_called_class();
        if (!isset(static::$instance[$class_name])) {
            static::$instance[$class_name] = new static();
        }
        return static::$instance[$class_name];
    }

    final protected function __clone(){}

    final protected function __wakeup(){}
}


/**
 * 返回值
 */
class ReturnValue
{
    protected $error = true;

    protected $value  = null;

    /**
     * ReturnValue constructor.
     *
     * @param bool $status
     * @param null $value
     */
    public function __construct($value = null, $status = true)
    {
        $this->error = !$status;
        $this->value = $value;
    }

    /**
     * @param $value
     */
    public function setValue($value)
    {
        $this->error = false;
        $this->value  = $value;
    }

    /**
     * @param $error
     */
    public function setError($error)
    {
        $this->error = true;
        $this->value = $error;
    }

    /**
     * @return boolean
     */
    public function isError()
    {
        return $this->error;
    }

    /**
     * @return mixed
     */
    public function getValue()
    {
        return $this->value;
    }
}


/**
 * 可配置接口
 */
interface IConfigurable
{
    public function get($key, $default = null, $withUpper = true);
}

/**
 * 可级联的配置扩展
 */
trait Configurable
{
    /**
     * @var Config
     */
    protected $config;

    /**
     * 异步器保存起来，防止提前被回收
     *
     * @var FileAsynchronizer[]
     */
    protected $holders;

    public function get($key, $default = null, $withUpper = true)
    {
        return $this->config->get($key, $default, $withUpper);
    }

    /**
     * 生成Config对象
     *
     * @param [] $item
     * @param IConfigurable $upper
     * @return Config
     */
    protected function createFileConfig($file, $upper)
    {
        $fa = new FileAsynchronizer($file);
        $config = new Config($upper, $fa);
        $config->load();
        return $config;
    }

    protected function createConfig($items, $upper)
    {
        $config = new Config($upper, $items);
        return $config;
    }
}


/**
 * 子对象管理器
 */
abstract class Manager
{
    /**
     * @var array|false 对象缓存 false表示不缓存
     */
    protected $objects = [];

    /**
     * 获取子对象实例
     *
     * @param string $name 子对象类名称
     * @param [] $arguments 实例参数
     *
     * @return mixed
     * @throws Exception
     */
    public function getObject($name)
    {
        // 不缓存的情况
        if($this->objects === false) return $this->createObject($name);

        // 缓存该对象
        $key = strtolower($name);
        if (!isset($this->objects[$key])) $this->objects[$key] = $this->createObject($name);

        return $this->objects[$key];
    }

    protected function has($name)
    {
        $key = strtolower($name);
        return isset($this->objects[$key]);
    }

    /**
     * 创建对象
     *
     * @param $name
     * @return object
     * @throws Exception
     */
    abstract protected function createObject($name);
}

class SimpleManager extends Manager
{
    /**
     * @var \Closure 实例创建器
     */
    protected $creator;

    /**
     * 构造器
     *
     * 通过creator实现子对象创建自定义
     *
     * @param \Closure $creator function($name, $arguments)
     * @param bool $shared 共享子对象
     *
     */
    public function __construct(\Closure $creator, $shared = true)
    {
        // 所有子对象不共享
        if (!$shared) $this->objects = false;

        $this->creator = $creator;
    }

    protected function createObject($name)
    {
        return ($this->creator)($name);
    }
}


/**
 * 该系列实现了 __get, __set 函数
 * 实现了属性的封装
 */
/**
 * 只读扩展
 */
trait TReadOnly
{
    /**
     * All of the attributes set on the container.
     *
     * @var array
     */
    protected $attributes = [];

    /**
     * Convert the Fluent instance to JSON.
     *
     * @param  int $options
     * @return string
     */
    public function toJson($options = 0)
    {
        return json_encode($this->attributes, $options);
    }

    /**
     * Dynamically retrieve the value of an attribute.
     *
     * @param  string $key
     * @return mixed
     */
    public function __get($key)
    {
        $getter = 'get' . ucfirst($key);

        // 方法优先
        if (method_exists($this, $getter)) return $this->$getter();

        return $this->get($key);
    }

    /**
     * Get an attribute from the container.
     *
     * @param  string|null $key
     * @param  mixed|null $default
     * @return mixed
     */
    public function get($key = null, $default = null)
    {
        if (null === $key)  return $this->attributes;
        return  array_isset($this->attributes, $key, $default);
    }

    /**
     * Dynamically check if an attribute is set.
     *
     * @param  string $key
     * @return bool
     */
    public function __isset($key)
    {
        return $this->has($key);
    }

    public function has($key)
    {
        return isset($this->attributes[$key]);
    }

    public function getKeys()
    {
        return array_keys($this->attributes);
    }
}

/**
 * 只读类
 */
class ReadOnly
{
    use TReadOnly;

    public function __construct(array $attributes)
    {
        $this->attributes = $attributes;
    }
}

/**
 * 自动设置扩展
 * 默认不写入
 */
trait AutoSet
{
    /**
     * 只对设置了SET函数的属性有效
     *
     * @param array $properties
     * @return $this
     */
    protected function property($properties)
    {
        foreach ($properties as $name => $value) {
            $this->auto_set_attribute($name, $value);
        }
        return $this;
    }

    /**
     * 自定义设置函数
     * @param $key
     * @param $value
     */
    abstract protected function auto_set_attribute($key, $value);
}

/**
 * 可读写属性扩展
 *
 */
trait Attribute
{
    use TReadOnly;
    use AutoSet;

    /**
     * 自定义设置函数
     * @param $key
     * @param $value
     */
    protected function auto_set_attribute($key, $value)
    {
        $this->$key = $value;
    }

    /**
     * Dynamically set the value of an attribute.
     *
     * @param  string $key
     * @param  mixed $value
     * @return void
     */
    public function __set($key, $value)
    {
        $setter = 'set' . ucfirst($key);

        // 方法优先
        if (method_exists($this, $setter)) {
            $this->$setter($value);
        }else{
            $this->attributes[$key] = $value;
        }
    }
}


/**
 * 中间件流水线，实现洋葱模式
 */
class Pipeline
{
    /**
     * @var callable
     */
    protected $middleware_creator = null;

    /**
     * Pipeline constructor.
     * @param $middleware_creator
     */
    public function __construct($middleware_creator =null)
    {
        if(is_callable($middleware_creator))
            $this->middleware_creator = $middleware_creator;
        else
            $this->middleware_creator = default_middleware_creator();
    }

    /**
     * 启动洋葱型流水线
     *
     * @param $middleware
     * @param $handler
     * @param $context
     * @return mixed
     *
     */
    public function start($middleware, $handler, $context)
    {
        $func =  array_reduce(array_reverse($middleware), function ($next, $item){
            // 闭包直接返回
            if(is_callable($item)) return $item($next);
            // 搜索中间件对象
            if(is_string($item) and $this->middleware_creator){
                /** @var Middleware $obj */
                $obj = ($this->middleware_creator)($item);
                if($obj) return $obj->machine($next);
            }
            // 跳过
            return $next;
        }, $handler);
        return $func($context);
    }
}

/**
 * 中间件接口
 */
Interface Middleware
{
    /**
     * @param \Closure $next
     * @return \Closure
     */
    public function machine(\Closure $next) : \Closure;
}


/**
 * 存储器接口
 */
interface IStorage
{
    /**
     * 根据ID获取信息
     *
     * @param int|string $key
     * @param mixed $column
     *   true: include文件   --File
     *   false: 直接获取Persister中的值  --Synchronizer
     *   string[]|string: 数据列 --ORM
     *   string[]|string: 文件属性 --File
     *   array: 参数 --File
     *   mixed: default 一般情况
     *
     * @return mixed
     * @throws Exception
     */
    public function get($key, $column = null);

    /**
     * 批量获取
     *
     * @param string[]|int[] $keys
     * @param string[] $column
     *
     * @return mixed
     * @throws Exception
     */
    public function getMulti($keys, $column = null);

    /**
     * 批量设置
     *   1: [key => value]
     *   2: value, keys
     *
     * @param mixed $pairs 键值对/统一值
     * @param array $keys  键数组
     *
     * @return int 影响的行数
     * @throws Exception
     */
    public function set($pairs, $keys = null);

    /**
     * 删除
     *
     * @param mixed $keys
     *
     * @return int 影响的行数
     * @throws Exception
     */
    public function delete($keys);

    /**
     * 是否为持久化存储器
     *
     * @return boolean
     */
    // public function isPersister();

}

/**
 * 持久化接口
 */
interface IPersister extends IStorage
{
    /**
     * 新增
     * @param mixed $value
     *
     * @return int|string id/key
     * @throws Exception
     */
    public function add($value);

    /**
     * 失效时间
     *
     * @param $key
     * @return mixed
     */
    public function getExpire($key);
}

/**
 * 可查询接口
 */
interface IQueryProvider
{
    /**
     * 按条件获取Keys
     *
     * @param $where
     * @param array $options
     * @return array
     * @throws Exception
     */
    public function getKeys($where, $options = []);

    /**
     * 高级查询
     *
     * @param string|array $columns
     * @param array $conditions
     * @param array $option
     * @param int $fetch_model
     * @return array
     * @throws Exception
     */
    public function query($columns, $conditions, $option = [], $fetch_model = null);
}

interface IQueryablePersister extends IPersister, IQueryProvider {}

/**
 * 异步接口
 */
interface IAsync
{
    /**
     * @return bool|null
     */
    public function load();

    /**
     * @param mixed $values
     * @return bool|null
     */
    public function save($values);
}

/**
 * 缓存器接口
 */
interface ICache extends IStorage
{
    /**
     * @param string|int $key
     *   The key for which to check existence.
     *
     * @param null|\DateTime $expire
     *
     * @return bool
     */
    public function hasItem($key, $expire = null);

    /**
     * 清空缓存
     */
    public function clear();
}


/**
 * 行为链
 */
abstract class Behavior
{
    /**
     * @var Behavior 链式结构
     */
    protected $next = null;

    /**
     * @var string
     */
    protected $name;

    /**
     * @return string 行为名称
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * 插入到指定行为或拼接到末端
     *
     * @param Behavior $next 要插入的行为链
     * @param string   $name 插入到行为$name处
     * @return Behavior
     */
    public function push(Behavior $next, $name = null)
    {
        if($name and $name === $this->name){
            if($this->next) $next->push($this->next);
            $this->next = $next;
        }elseif($this->next){
            $this->next->push($next,$name);
        }else{
            $this->next = $next;
        }

        return $this;
    }

    /**
     * 执行行为链
     *
     * @param mixed $params  参数
     * @param array $context 上下文
     * @param int   $mode    执行模式
     *
     * @return bool
     */
    final public function invoke(&$params = null, &$context = [], $mode = Event::MODE_TRUE)
    {
        $r = $this->run($params,$context);

        if (
            ($mode === Event::MODE_TRUE  and  $r) or
            ($mode === Event::MODE_FALSE and !$r) or
            $mode === Event::MODE_CONTINUE
        ){
            return (($this->next)?$this->next->invoke($params,$context):true);
        }

        return $r;
    }

    /**
     * 执行行为 run方法是Behavior唯一的接口
     *
     * @param mixed $params  行为参数
     * @param array $context 行为上下文
     *
     * @return bool 返回true继续
     */
    abstract public function run(&$params = null, &$context = []);
}

/**
 * 触发器
 */
abstract class Event
{
    const MODE_CONTINUE =  2;
    const MODE_TRUE     =  1;
    const MODE_FALSE    =  0;

    /**
     * @var Behavior 行为链
     */
    protected $behavior;

    public function fire(&$params = null, &$context = [], $mode = Event::MODE_TRUE)
    {
        if($this->behavior)
            return $this->behavior->invoke($params, $context, $mode);

        return null;
    }

    public function binding($behaviors)
    {
        // 字符串分解
        if (!is_array($behaviors)) {
            $behaviors = explode('|', $behaviors);
        }
        //
        if (empty($behaviors)) return ;

        foreach($behaviors as $behavior => $arguments){
            $this->insertBehavior($this->getBehaviorByName($behavior,$arguments));
        }
    }

    protected function insertBehavior($behavior)
    {
        if(!$behavior) return ;

        if($this->behavior) {
            $this->behavior->push($behavior);
        }else{
            $this->behavior = $behavior;
        }
    }

    abstract function getBehaviorByName($behavior, $arguments = null);
}


/**
 * 独立体接口,独立的配置管理
 */
interface Independent
{
    /**
     * @return string 配置文件、语言文件基本路径
     */
    public function getDir();
}


/**
 * 自动加载器
 */
abstract class Holder
{
    /**
     * @var array 数据
     */
    protected $values =[];

    /**
     * @var string[] 已加载的文件
     */
    protected $loaded = [];


    /**
     * 注册条目
     *
     * @param string $dir
     * @param string $key
     */
    public function regDir($dir, $key = null)
    {
        $file = $this->compile($dir, $key);

        if(!isset($this->loaded[$file])) $this->inject($file);
    }

    /**
     * 注入入口获取
     *
     * @param string $dir 路径名
     * @param string $key 文件名
     * @return string
     */
    abstract protected function compile($dir, $key = null);

    /**
     * 数据注入动作
     *
     * @param string $file
     */
    protected function inject($file)
    {
        // TODO 注册失败也会显示已注册
        $this->loaded[$file] = true;

        $array = File::get($file,true);
        if($array) $this->values = array_merge($this->values, $array);
    }
}

/**
 * 模板编译引擎
 */
interface Engine
{
    /**
     * 加载模板
     * @param string $templateFile 模板文件
     *
     * @return string|false
     * @throws Exception
     */
    public function fetch($templateFile);
}


/**
 * 用户中心
 * @package J
 */
interface UCenter
{
    /**
     * 登录用户动作
     * @return array|false
     */
    public function loginUser();

    /**
     * 根据角色获取可执行的操作
     * @param array $roles
     * @return mixed
     */
    public function getAuthorize($roles);

    /**
     * 获取当前用户角色
     * @param $user
     * @return mixed
     */
    public function getRoles($user);


    /**
     * 用户隶属的部门
     * @param int $user
     *
     * @return array
     */
    public function getDepartments($user);

    /**
     * 获取指定用户的权限信息
     * @param $user
     * @return array|mixed
     */
    public function getUserAuthorize($user);
}
